#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
上下文分析器
用于判断代码位置是否在字符串、注释、import语句中
防止误替换字符串字面量和注释中的符号
"""

import re
from typing import Tuple, Optional
from dataclasses import dataclass


@dataclass
class CodeContext:
    """代码上下文"""
    in_string: bool = False
    in_comment: bool = False
    in_import: bool = False
    string_type: Optional[str] = None  # 'single', 'double', 'triple_single', 'triple_double'
    comment_type: Optional[str] = None  # 'line', 'block'


class ContextAnalyzer:
    """
    上下文分析器

    用于分析代码中特定位置的上下文，判断是否可以安全地进行符号替换
    """

    def __init__(self, language: str = 'swift'):
        """
        初始化上下文分析器

        Args:
            language: 编程语言 ('swift', 'objc', 'kotlin', 'java')
        """
        self.language = language
        self._build_patterns()

    def _build_patterns(self):
        """构建语言特定的模式"""
        if self.language in ['swift', 'kotlin', 'java', 'objc']:
            self.line_comment = '//'
            self.block_comment_start = '/*'
            self.block_comment_end = '*/'
        elif self.language == 'python':
            self.line_comment = '#'
            self.block_comment_start = '"""'
            self.block_comment_end = '"""'
        else:
            # 默认使用C风格注释
            self.line_comment = '//'
            self.block_comment_start = '/*'
            self.block_comment_end = '*/'

    def is_in_string(self, pos: int, content: str) -> Tuple[bool, Optional[str]]:
        """
        检查位置是否在字符串中

        Args:
            pos: 检查位置
            content: 完整内容

        Returns:
            (是否在字符串中, 字符串类型)
        """
        before = content[:pos]

        # 先检查三引号字符串（Python/Swift多行字符串）
        # 必须在单/双引号之前检查，避免误判
        if '"""' in before:
            triple_double = before.count('"""')
            if triple_double % 2 == 1:
                return True, 'triple_double'

        if "'''" in before:
            triple_single = before.count("'''")
            if triple_single % 2 == 1:
                return True, 'triple_single'

        # 检查双引号字符串
        double_quotes = self._count_unescaped(before, '"')
        if double_quotes % 2 == 1:
            return True, 'double'

        # 检查单引号字符串
        single_quotes = self._count_unescaped(before, "'")
        if single_quotes % 2 == 1:
            return True, 'single'

        return False, None

    def _count_unescaped(self, text: str, char: str) -> int:
        """
        计算未转义的字符数量

        Args:
            text: 文本
            char: 要计数的字符

        Returns:
            未转义的字符数量
        """
        count = 0
        i = 0
        while i < len(text):
            if text[i] == '\\':
                i += 2  # 跳过转义字符和下一个字符
                continue
            if text[i] == char:
                count += 1
            i += 1
        return count

    def is_in_comment(self, pos: int, content: str) -> Tuple[bool, Optional[str]]:
        """
        检查位置是否在注释中

        Args:
            pos: 检查位置
            content: 完整内容

        Returns:
            (是否在注释中, 注释类型)
        """
        # 检查单行注释
        line_start = content.rfind('\n', 0, pos)
        if line_start == -1:
            line_start = 0
        else:
            line_start += 1

        line_before = content[line_start:pos]

        # 检查单行注释符号（// 或 #）
        if self.line_comment in line_before:
            comment_pos = line_before.find(self.line_comment)
            before_comment = line_before[:comment_pos]

            # 确保注释符号不在字符串中
            in_string, _ = self.is_in_string(line_start + comment_pos, content)
            if not in_string:
                return True, 'line'

        # 检查多行注释 /* */
        if self.language in ['swift', 'kotlin', 'java', 'objc']:
            before_pos = content[:pos]

            # 找到所有 /* 和 */ 的位置
            block_starts = [m.start() for m in re.finditer(r'/\*', before_pos)]
            block_ends = [m.start() for m in re.finditer(r'\*/', before_pos)]

            # 过滤掉在字符串中的注释符号
            block_starts = [p for p in block_starts
                          if not self.is_in_string(p, content)[0]]
            block_ends = [p for p in block_ends
                        if not self.is_in_string(p, content)[0]]

            # 检查是否在未闭合的块注释中
            if len(block_starts) > len(block_ends):
                return True, 'block'

        return False, None

    def is_in_import(self, pos: int, content: str) -> bool:
        """
        检查位置是否在import语句中

        Args:
            pos: 检查位置
            content: 完整内容

        Returns:
            是否在import语句中
        """
        # 获取当前行
        line_start = content.rfind('\n', 0, pos)
        if line_start == -1:
            line_start = 0
        else:
            line_start += 1

        line_end = content.find('\n', pos)
        if line_end == -1:
            line_end = len(content)

        line = content[line_start:line_end].strip()

        # 检查各种import形式
        import_patterns = [
            r'^import\s+',           # Swift, Java, Kotlin
            r'^from\s+.+\s+import',  # Python
            r'^#import\s+',          # Objective-C
            r'^@import\s+',          # Objective-C modules
            r'^#include\s+',         # C/C++
        ]

        for pattern in import_patterns:
            if re.match(pattern, line):
                return True

        return False

    def analyze_position(self, pos: int, content: str) -> CodeContext:
        """
        分析位置的完整上下文

        Args:
            pos: 检查位置
            content: 完整内容

        Returns:
            CodeContext对象
        """
        in_string, string_type = self.is_in_string(pos, content)
        in_comment, comment_type = self.is_in_comment(pos, content)
        in_import = self.is_in_import(pos, content)

        return CodeContext(
            in_string=in_string,
            in_comment=in_comment,
            in_import=in_import,
            string_type=string_type,
            comment_type=comment_type
        )

    def is_safe_to_replace(self, pos: int, content: str) -> bool:
        """
        检查位置是否可以安全替换

        Args:
            pos: 检查位置
            content: 完整内容

        Returns:
            是否可以安全替换（不在字符串、注释、import中）
        """
        context = self.analyze_position(pos, content)

        # 不在字符串、注释、import中才能替换
        return not (context.in_string or context.in_comment or context.in_import)